package com.aotain.common;

import org.apache.log4j.Logger;

/**
 * 2016/02/25 Hurst 指数计算
 * @author Administrator
 *
 */
public class Hurst {
	
	//时间序列
	double[] _data;
	
	public Hurst(double[] data)
	{
		_data = data;
	}
	
	
	/**
	 * 计算hurst指数
	 * @return
	 */
	public double Calculate()
	{
		
		try
		{
		
			//时间序列长度
			int nTotal = _data.length;
			int NoOfDataPoints = nTotal;
			double[][] Result = new double[NoOfDataPoints / 2][2];
			
			int A = 2;
			
			while(A <= NoOfDataPoints / 2)
			{
				//再次定义数组变量(需要不通精度的值)
				int NoOfPeriods = NoOfDataPoints / A;
				int DOfPeriods = (int)Math.ceil((double)NoOfDataPoints /(double)A);
				double DoubleOfPeriods = (double)NoOfDataPoints /(double)A;
				
				
				
				double[] Array1 = new double[NoOfPeriods];
				double[][] Array2 = new double[A][NoOfPeriods];
				double[] S = new double[NoOfPeriods];
				double[] R = new double[NoOfPeriods];
				
				double RS = 0;
				//求得各个子区间均值
				int i = 0;
				while(i <= NoOfPeriods - 1)
				{
					double e = 0;
					for (int PeriodNo = 0;PeriodNo < A; PeriodNo++)
					{
						e = e + _data[PeriodNo + i * A];
						//
					}
					Array1[i] = e / (double)A;
					i = i + 1;
					
					
				}
				//求得各个子区间的累积截距和极差
				i = 0;
				while (i < DOfPeriods - 1)
				{
					double m = 0;
					double e = 0;
					for(int PeriodNo = 0; PeriodNo<= A-1; PeriodNo++)
					{
						m = m + Math.pow((_data[PeriodNo + i * A] - Array1[i]) , 2);
						e = e + (_data[PeriodNo + i * A] - Array1[i]);
						Array2[PeriodNo][i] = e;
					}
					// 比较最大值与最小值
					double Maxi = Array2[0][i];
					double Mini = Array2[0][i];
					for(int n = 0;n <= A - 1;n++)
					{
						if(Array2[n][i] > Maxi)
							Maxi = Array2[n][i];
						if(Array2[n][i] < Mini)
							Mini = Array2[n][i];
					}
					//求得 R/S 值
					R[i] = Maxi - Mini;
					S[i] = Math.sqrt(m / A);
					RS = RS + R[i] / S[i];
//					System.out.println("A:" + A + "  i:" + i 
//							+ " RS:" + RS + " R:" + R[i] + " S:" + S[i]);
//					System.out.println("m:" + m);
					i = i + 1;
					
				}
				//将 V 统计量表的数据输出到 Excel 表格中
	//				Worksheets("sheet1").Cells(A + 2, 5).Value = (RS / NoOfPeriods) / Sqr(A)
	//				Worksheets("sheet1").Cells(A + 2, 6).Value = Log(A)
//				double v1 = (RS / (DoubleOfPeriods)) / Math.sqrt(A);
//				double v2 = Math.log(A);
//				
//				System.out.println("V1:" + v1 + "  V2:" + v2 + "  RS:" + RS + " NoOfPeriods:" + DoubleOfPeriods + " A:" + A);
				
				//将计算结果装入 Result （）数组中
				
				Result[A-1][0] = Math.log(A);
				Result[A-1][1] = Math.log(RS / DoubleOfPeriods);
				A = A + 1;
			}
			
			//对方程 Log(R/S)=Log(c) + H · Log(n)+ ε 进行线性回归，估计出斜率 H 就是 Hurst 指数
			double sumx = 0;
			double Sumy = 0;
			double Sumxy = 0;
			double Sumxx = 0;
			int NoOfPlottedPoints = NoOfDataPoints / 2;
			for (int i = 1;i <= NoOfPlottedPoints - 1;i++)
			{
				sumx = sumx + Result[i][0];
				Sumy = Sumy + Result[i][1];
				Sumxy = Sumxy + (Result[i][0]) * (Result[i][1]);
				Sumxx = Sumxx + (Result[i][0]) * (Result[i][0]);
			}
			double H = (Sumxy - ((sumx * Sumy) / NoOfPlottedPoints)) / (Sumxx - ((sumx * sumx) / NoOfPlottedPoints));
			return H;
		}
		catch(Exception ex)
		{
			Logger.getLogger(Hurst.class).error("Hurst Calculate Error",ex);
			throw ex;
		}
	}

}

